package com.tiancheng.trade.order.channel;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiancheng.trade.commom.core.exception.BusinessException;
import com.tiancheng.trade.commom.core.exception.error.BusinessErrorInfoEnum;
import com.tiancheng.trade.order.bo.SubOrderRefundBO;
import com.tiancheng.trade.order.bo.SubOrderRefundTotalBo;
import com.tiancheng.trade.order.enums.RefundStatusEnum;
import com.tiancheng.trade.commom.web.feign.PaymentFeignService;
import com.tiancheng.trade.commom.web.model.request.RefundDTO;
import com.tiancheng.trade.order.mapper.RefundOrdersDetailMapper;
import com.tiancheng.trade.order.model.Order;
import com.tiancheng.trade.order.model.RefundOrders;
import com.tiancheng.trade.order.model.RefundOrdersDetail;
import com.tiancheng.trade.order.model.SubOrder;
import com.tiancheng.trade.order.service.SubOrderService;
import com.tiancheng.trade.order.util.helper.OrderIdHelper;
import com.tiancheng.trade.order.vo.open.order.OpenRefundVO;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 支付渠道抽象
 *
 * @author likailun
 * @date 2021/4/20
 */
@Service
public abstract class AbstractPayChannel {
    @Resource
    protected OrderIdHelper orderIdHelper;
    @Autowired
    protected RefundOrdersDetailMapper refundOrdersDetailMapper;
    @Resource
    protected SubOrderService subOrderService;
    @Resource
    protected PaymentFeignService paymentFeignService;

    /**
     * 申请退款单
     */
    public abstract RefundOrders generateRefunds(OpenRefundVO refundVO, Order order);

    /**
     * 创建并提交退款
     *
     * @param refundVO 退款参数
     * @param refundOrdersDetails  退款流水
     */
    public abstract RefundDTO createAndSubmit(OpenRefundVO refundVO, RefundOrders refundOrders);

    /**
     * 检查子订单的退款金额
     *
     * @param order         总订单id
     * @param subOrders       申请退款子订单
     * @param submitRefundMap 申请退款的子订单退款信息
     * @return 已存在退款的订单信息(不包含本次提交的退款)
     * @throws BusinessException
     */
    protected Map<String, SubOrderRefundTotalBo> checkRefundAmount(Order order, List<SubOrder> subOrders, Map<String, Integer> submitRefundMap) throws BusinessException {
        // 子订单已经退的款
        String[] subOrderIds = subOrders.stream().map(SubOrder::getSubOrderId).toArray(String[]::new);
        List<SubOrderRefundTotalBo> subOrderRefunds = refundOrdersDetailMapper.sumForSubOrder(order.getOrderId(), subOrderIds);
        // 判断支付金额是否大于退款金额
        Map<String, SubOrderRefundTotalBo> refundTotalMap = new HashMap<>();
        for (SubOrder subOrder : subOrders) {
            int refundTotal = 0;
            List<SubOrderRefundTotalBo> subRefund = subOrderRefunds.stream().filter(s -> s.getSubOrderId().equals(subOrder.getSubOrderId())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(subRefund)) {
                // 该子订单已有退款状态为“IG”、“SC”的退款记录
                refundTotal += subRefund.get(0).getTotal();
            } else {
                // 不存在退款记录
                subRefund.add(new SubOrderRefundTotalBo(subOrder.getSubOrderId(), 0, 0,0,0));
            }
            if (submitRefundMap.get(subOrder.getSubOrderId()) != 0) {
                // 业务系统提交了退款金额
                refundTotal += submitRefundMap.get(subOrder.getSubOrderId()).intValue();
            } else {
                // 没有提交退款金额
                refundTotal += subOrder.getPayAmount();

            }
            BusinessErrorInfoEnum.ORDER_REFUND_AMOUNT_SHORT.assertIsTrue(subOrder.getPayAmount() >= refundTotal);
            // 设置子订单的总退款金额（包含本次提交的）
            subRefund.get(0).setTotal(refundTotal);
            refundTotalMap.put(subOrder.getSubOrderId(), subRefund.get(0));
        }
        return refundTotalMap;
    }

    /**
     * 退款失败时
     *
     * @param refundOrdersDetails
     */
    public void refundFail(List<RefundOrdersDetail> refundOrdersDetails) {
        if (CollectionUtils.isEmpty(refundOrdersDetails)) {
            BusinessErrorInfoEnum.ORDER_REFUND_NO_DATA.assertFail();
            return;
        }
        List<Long> refundIds = refundOrdersDetails.stream().map(RefundOrdersDetail::getId).collect(Collectors.toList());
        BusinessErrorInfoEnum.ORDER_REFUND_NO_DATA.assertIsTrue(CollectionUtils.isNotEmpty(refundIds));
        List<SubOrderRefundBO> subOrderRefundBOS = new ArrayList<>();
        refundOrdersDetails.forEach(refund -> {
            subOrderRefundBOS.add(new SubOrderRefundBO(refund.getOrderId(), refund.getSubOrderId(), 0, RefundStatusEnum.fail.getCode()));
        });
        subOrderService.refund(subOrderRefundBOS);
        RefundOrdersDetail updateRefundOrdersDetail = new RefundOrdersDetail();
        updateRefundOrdersDetail.setLastUpdDt(LocalDateTime.now());
        updateRefundOrdersDetail.setRefundStatus(RefundStatusEnum.fail.getCode());
        QueryWrapper<RefundOrdersDetail> conditions = new QueryWrapper<>();
        conditions.in("id", refundIds);
        refundOrdersDetailMapper.update(updateRefundOrdersDetail, conditions);
    }

}
